package com.acme.bankapp.domain.bank.email;

import java.util.LinkedList;
import java.util.List;

/**
 * Service to send notification emails in a separate thread.
 * 
 */
public class EmailService {
	private List<Email> queue = new LinkedList<Email>();
	private Thread worker = null;
	private volatile boolean canSendNotifications = true;

	private class EmailWorker implements Runnable {
		@Override
		public void run() {
			try {
				synchronized (queue) {
					while (canSendNotifications) {
						processQueue();
						queue.wait();
					}
					processQueue();
				}
			} catch (InterruptedException ex) {
				System.out.println("Email worker was interrupted.");
			}
			System.out.println("Email worker is shut down.");
		}

		private void processQueue() throws InterruptedException {
			while (!queue.isEmpty()) {
				Email email = queue.remove(0);
				System.out.println("[LISTENER] Notification email for client "
						+ email.getClient().getClientSalutation()
						+ " to be sent to " + email.getEmail() + ".");
			}
		}
	}

	/**
	 * Creates email service.
	 */
	public EmailService() {
		worker = new Thread(this.new EmailWorker());
		worker.start();
	}

	/**
	 * Adds email to the queue to be sent in a separate thread.
	 * 
	 * @param email
	 *            email to be sent
	 */
	public void sendNotificationEmail(Email email) {
		// using double-checked locking
		if (canSendNotifications) {
			synchronized (queue) {
				if (canSendNotifications) {
					queue.add(email);
					queue.notifyAll();
				} else {
					alertShuttingDown();
				}
			}
		} else {
			alertShuttingDown();
		}
	}

	private void alertShuttingDown() {
		System.out
				.println("Sorry, can't send another notification. Email service is about to shut down.");
	}

	/**
	 * Shuts down email service. Service clears the queue, sending rest of the
	 * notifications and returns control to the calling method.
	 */
	public void close() {
		synchronized (queue) {
			canSendNotifications = false;
			queue.notifyAll();
		}
		try {
			if (worker != null) {
				worker.join();
			}
			System.out.println("Email service is shut down.");
		} catch (InterruptedException ex) {
			System.out
					.println("Email service shutdown sequence was interrupted.");
		}
	}
}
